home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 4 / Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso / Development / Source / Telnet 2.6.1d1 4⁄26⁄94 Folder / source / vs / vsinterf.c < prev    next >
Text File  |  1994-03-17  |  47KB  |  1,604 lines

  1. /*
  2.  *
  3.  *      Virtual Screen Kernel Interface
  4.  *              (vsinterf.c)
  5.  *
  6.  *      by Gaige B. Paulsen
  7.  *
  8.  *    This file contains the control and interface calls for the NCSA
  9.  *  Virtual Screen Kernal.
  10.  *
  11.  *      VSinit(maxwidth)                    - Initialize the VSK
  12.  *      VSnewscreen(maxlines,scrnsave)    - Initialize a new screen.
  13.  *      VSdetach(w)                        - Detach screen w
  14.  *      VSredraw(w,x1,y1,x2,y2)            - redraw region for window w
  15.  *      VSwrite(w,ptr,len)                - write text @ptr, length len
  16.  *      VSclear(w)                        - clear w's real screen
  17.  *      VSkbsend(w,k,echo)                - send keycode k's rep. out window w (w/echo if req.)
  18.  *      VSclearall(w)                        - clear w's real and saved screen
  19.  *      VSreset(w)                        - reset w's emulator (as per TERM)
  20.  *      VSgetline(w,y)                    - get a ptr to w's line y
  21.  *      VSsetrgn(w,x1,y1,x2,y2)            - set local display region
  22.  *      VSscrolback(w,n)                    - scrolls window w back n lines
  23.  *      VSscrolforward(w,n)                - scrolls window w forward n lines
  24.  *      VSscrolleft(w,n)                     - scrolls window w left  n columns
  25.  *      VSscrolright(w,n)                     - scrolls window w right n columns
  26.  *      VSscrolcontrol(w,scrlon,offtop)    - sets scroll vars for w
  27.  *      VSgetrgn(w,&x1,&y1,&x2,&y2)        - returns set region
  28.  *      VSsnapshot(w)                          - takes a snapshot of w
  29.  *      VSgetlines(w)                        - Returns current # of lines
  30.  *      VSsetlines(w, lines)                - Sets the current # of lines to lines
  31.  *    
  32.  *        Version Date    Notes
  33.  *        ------- ------  ---------------------------------------------------
  34.  *        0.01    861102  Initial coding -GBP
  35.  *        0.10    861113  Added some actual program to this file -GBP
  36.  *        0.15    861114  Initiated Kludge Operation-GBP
  37.  *        0.50    8611VSPBOTTOM  Parameters added to VSnewscreen -GBP
  38.  *        0.90    870203    Added the kbsend routine -GBP
  39.  *        2.1        871130    NCSA Telnet 2.1 -GBP
  40.  *        2.2     880715    NCSA Telnet 2.2 -GBP
  41.  *
  42.  */
  43.  
  44. #ifdef MPW
  45. #pragma segment VS
  46. #endif
  47.  
  48. #include "TelnetHeader.h"
  49.  
  50. #define VSMASTER
  51.  
  52. #include <ToolUtils.h>    /* BYU 2.4.18 - for GetIndString() */
  53. #include <stdio.h>
  54.  
  55. #include <String.h>
  56.  
  57. #include "rsmac.proto.h"
  58. #include "vsem.proto.h"
  59. #include "vsdata.h"
  60. #include "vskeys.h"
  61. #include "vsinit.h"
  62. #include "vsintern.proto.h"
  63. #include "Wind.h"
  64. #include "DlogUtils.proto.h"
  65. #include "maclook.proto.h"
  66. #include "errors.proto.h"
  67. #include "debug.h"
  68.  
  69. #define DEBUGMAC
  70.  
  71. #include "vsinterf.proto.h"
  72.  
  73. extern TelInfoRec *TelInfo;
  74. extern WindRec    *screens;
  75. extern long        TempItemsDirID;
  76. extern short    TempItemsVRefNum;
  77.  
  78. short
  79.   /* Internal variables for use in managing windows */
  80.     VSmax = 0, /* max nr screens allowed */
  81.     VSinuse = 0; /* nr screens actually in existence */
  82. VSscrndata *VSscreens;
  83.  
  84. short VSinit
  85.   (
  86.     short max /* max nr screens to allow */
  87.   )
  88.   /* initializes virtual screen and window handling. */
  89.   {
  90.     short i;
  91.  
  92.     RSinitall(max);
  93.     VSmax = max;
  94.     VSIwn = 0;
  95.     if ((VSscreens = (VSscrndata *) NewPtr(max * sizeof(VSscrndata))) == 0L)
  96.         return(-2);
  97.     for (i = 0; i < max; i++)
  98.       {
  99.         VSscreens[i].loc = 0L;
  100.         VSscreens[i].stat = 0;
  101.       } /* for */
  102.     return(0);
  103.   } /* VSinit */
  104.  
  105.  
  106. short VSiscapturing(short w) {                                /* BYU 2.4.18 */
  107.     return(VSscreens[w].captureRN);                    /* BYU 2.4.18 */
  108. }                                                        /* BYU 2.4.18 */
  109.  
  110. Boolean VSopencapture(short scrn_num, short w)
  111. {
  112.     #pragma unused (scrn_num)
  113.     static short    captNumber = 1;
  114.     short            VRefNum;
  115.     long            DirID;
  116.     Str255            filename;
  117.     Str32            numstring;
  118.     Point            where = {100,100};
  119.     SFReply            sfr;
  120.     long            junk = 0;
  121.     OSErr            err;
  122.     
  123.     NumToString(captNumber++, numstring);
  124.     GetIndString(filename, MISC_STRINGS, CAPTFILENAME);
  125.     filename[++(filename[0])] = ' ';
  126.     pstrcat(filename, numstring);
  127.     
  128.     SFPutFile(where, "\pSave captured text as:", filename, NULL, &sfr);
  129.     if (sfr.good) {
  130.         (void) GetWDInfo(sfr.vRefNum, &VRefNum, &DirID, &junk);
  131.  
  132.         err = HCreate(VRefNum, DirID, sfr.fName, 
  133.                     gApplicationPrefs->CaptureFileCreator, 'TEXT');
  134.         if (err == dupFNErr) {
  135.             HDelete(VRefNum, DirID, sfr.fName);
  136.             err = HCreate(VRefNum, DirID, sfr.fName,
  137.                             gApplicationPrefs->CaptureFileCreator, 'TEXT');
  138.             }
  139.             
  140.         if (err != noErr)
  141.             OperationFailedAlert(CANT_CREATE_FILE, 500, err);
  142.         else {        
  143.             err = HOpen(VRefNum, DirID, sfr.fName, fsRdWrPerm,
  144.                 &VSscreens[w].captureRN);
  145.             if (err != noErr) OperationFailedAlert(CANT_OPEN_FILE, 501, err);
  146.             else {
  147.                 SetEOF(VSscreens[w].captureRN, (long) 0);
  148.                 return(TRUE);
  149.                 }
  150.             }
  151.         }
  152.         
  153.     return(FALSE);
  154. }
  155.  
  156. void VSclosecapture(short w) {                                    /* BYU 2.4.18 */
  157.     FSClose(VSscreens[w].captureRN);                    /* BYU 2.4.18 */
  158.     VSscreens[w].captureRN = 0;                            /* BYU 2.4.18 */
  159. }                                                        /* BYU 2.4.18 */
  160.  
  161. void VScapture(unsigned char *ptr, short len) {        /* BYU 2.4.18 */
  162.     long ln = len;                                /* BYU 2.4.18 */
  163.     if (VSscreens[VSIwn].captureRN) {            /* BYU 2.4.18 */
  164.         unsigned char captbuf[512];                /* BYU 2.4.18 */
  165.         unsigned char *ptr2,*ptr3;                /* BYU 2.4.18 */
  166.         ptr2 = ptr;                                /* BYU 2.4.18 */
  167.         ptr3 = &captbuf[0];                        /* BYU 2.4.18 */
  168.         for (len = 0; len < ln; len++) {        /* BYU 2.4.18 */
  169.             if (*ptr2 >= 32 ||                     /* BYU 2.4.18 */
  170.                 *ptr2 == 13 ||                    /* BYU 2.4.18 */
  171.                 *ptr2 ==  9)                    /* BYU 2.4.18 */
  172.                 *(ptr3++) = *(ptr2++);            /* BYU 2.4.18 */
  173.             else {                                /* BYU 2.4.18 */
  174.                 ptr2++;                            /* BYU 2.4.18 */
  175.                 ln--;                            /* BYU 2.4.18 */
  176.             }                                    /* BYU 2.4.18 */
  177.         }                                        /* BYU 2.4.18 */
  178.         if (ln > 0) {                                                    /* BYU 2.4.18 */
  179.             if (FSWrite(VSscreens[VSIwn].captureRN, &ln, captbuf)) {    /* BYU 2.4.18 */
  180.                 FSClose(VSscreens[VSIwn].captureRN);                    /* BYU 2.4.18 */
  181.                 VSscreens[VSIwn].captureRN = 0;                            /* BYU 2.4.18 */
  182.             }                                            /* BYU 2.4.18 */
  183.         }                                            /* BYU 2.4.18 */
  184.     }                                                /* BYU 2.4.18 */
  185. }                                                    /* BYU 2.4.18 */
  186.  
  187. short    VSisprinting(short w)
  188. {
  189.     return((VSscreens[w].loc)->prredirect);
  190. }
  191.  
  192. void    ClosePrintingFile(short w)
  193. {
  194.     OSErr sts;
  195.     char tmp[80];
  196.  
  197.     putln("Attempting to remove print file");
  198.     
  199.     if (sts=FSClose ((VSscreens[w].loc)->refNum)) {
  200.         SysBeep(1);
  201.         sprintf(tmp,"FSClose: ERROR %d",sts); putln(tmp);
  202.         }
  203.     if (sts=HDelete(TempItemsVRefNum, TempItemsDirID, (StringPtr)VSIw->fname)) {
  204.         SysBeep(1);
  205.         sprintf(tmp,"HDelete: ERROR %d",sts); putln(tmp);
  206.         }
  207. }
  208.  
  209. short VSvalids
  210.   (
  211.     short w
  212.   )
  213.   /* validates a virtual screen number and sets it as the
  214.     current screen for subsequent operations if success.
  215.     Returns 0 iff success. */
  216.   {
  217.     if (VSinuse == 0)
  218.         return(-5); /* -5=no ports in use */
  219.     if (VSIwn == w)
  220.         return(0);    /* Currently set to that window */
  221.     if ((w > VSmax) || (w < 0))
  222.         return(-6); /* blown out the top of the stuff */
  223.     VSIwn = w;
  224.     if (VSscreens[w].stat != 1)
  225.         return(-3);/* not currently active */
  226.     VSIw = VSscreens[w].loc;
  227.     if (VSIw == 0L)
  228.         return(-3); /* no space allocated */
  229.     return(0);
  230.   } /* VSvalids */
  231.  
  232. VSscrn *VSwhereis(short i) /* screen number */
  233.   /* returns a pointer to the structure for the specified screen. */
  234.   {
  235.     VSvalids(i);
  236.     return(VSIw);
  237.   } /* VSwhereis */
  238.  
  239. void VSIclrbuf
  240.   (
  241.     void
  242.   )
  243.   /* clears out the text and attribute buffers for the current screen.
  244.     All text characters are set to blanks, and all attribute bytes
  245.     are set to zero. Doesn't update the display. */
  246.   {
  247.     register short j, i;
  248.     register char *ta, *tx;
  249.  
  250.     for (i = 0; i <= VSIw->lines; i++)
  251.       {
  252.         ta = &VSIw->attrst[i]->text[0];
  253.         tx = &VSIw->linest[i]->text[0];
  254.         for (j = 0; j <= VSIw->allwidth; j++)
  255.           {
  256.             *ta++ = 0;
  257.             *tx++ = ' ';
  258.           } /* for */
  259.       } /* for */
  260.   } /* VSIclrbuf */
  261.  
  262. short VSnewscreen
  263.   (
  264.     short maxlines, /* max lines to save in scrollback buffer */
  265.     short screensave, /* whether to have a scrollback buffer */
  266.     short maxwid, /* number of columns on screen */
  267.     short IDC, /* NCSA 2.5:whether to be smart and scroll things on character
  268.         insertion/deletion. Currently always passed as 1 (in the
  269.         only call, from RSnewwindow in rsmac.c). Just as well,
  270.         because the two places (both in vsintern.c) where this does
  271.         matter don't do correct redrawing otherwise. */
  272.     short forcesave    /* NCSA 2.5: force lines to be saved */
  273.   )
  274.   /* creates a new virtual screen, and returns its number. */
  275.   {
  276.     VSlinePtr tt;
  277.  
  278.     if (maxlines < VSDEFLINES)
  279.         maxlines = VSDEFLINES;
  280.  
  281.     if (VSinuse >= VSmax)
  282.       /* too many screens in existence */
  283.         return(-1);
  284.     VSIwn = 0;
  285.     while ((VSIwn < VSmax) && (VSscreens[VSIwn].stat == 1))
  286.         VSIwn++;
  287.     if (VSIwn >= VSmax)
  288.       /* shouldn't occur? */
  289.         return(-1);
  290.  
  291.     if (VSscreens[VSIwn].stat == 2)
  292.       {
  293.       /* recycling an old screen structure */
  294.         VSIw = VSscreens[VSIwn].loc;
  295.         if (VSIw == 0L)
  296.             return(-7);
  297.       }
  298.     else
  299.       /* create a new screen structure */
  300.         if ((VSscreens[VSIwn].loc = VSIw = (VSscrn *) NewPtr(sizeof(VSscrn))) == 0L)
  301.           {
  302.             VSscreens[VSIwn].loc = 0L;
  303.             return(-2);
  304.           } /* if */
  305.     if (VSscreens[VSIwn].stat != 2)
  306.       {
  307.         VSIw->maxlines = maxlines;
  308.         VSIw->numlines = 0;
  309.       } /* if */
  310.     VSscreens[VSIwn].captureRN = 0;        /* BYU 2.4.18 - capture file's RefNum */
  311.     VSIw->id = 'VSCR';
  312.     VSIw->maxwidth = maxwid - 1;
  313.     VSIw->allwidth = 131;                /* NCSA: SB - always allocate max lines */
  314.     VSIw->savelines = screensave;
  315.     VSIw->forcesave = forcesave;        /* NCSA 2.5 */
  316.     VSIw->attrib = 0;
  317.     VSIw->Pattrib = -1; /* initially no saved attribute */
  318.     VSIw->x = 0;
  319.     VSIw->y = 0;
  320.     VSIw->charset = 0;
  321.     VSIw->G0 = 0;
  322.     VSIw->G1 = 1;
  323.     VSIw->VSIDC = IDC;
  324.     VSIw->DECAWM = 0;
  325.     VSIw->DECCKM = 0;
  326.     VSIw->DECPAM = 0;
  327.     VSIw->DECORG = 0;
  328.     VSIw->IRM = 0;
  329.     VSIw->escflg = 0;
  330.     VSIw->top = 0;
  331.     VSIw->bottom = 23;
  332.     VSIw->parmptr = 0;
  333.     VSIw->Rtop = 0;
  334.     VSIw->Rleft = 0;
  335.     VSIw->Rright = 79;
  336.     VSIw->Rbottom = 23;
  337.     VSIw->ESscroll = 1;
  338.   /* shouldn't the following three statements be conditional on
  339.     *not* recycling an existing screen structure? */
  340.     VSIw->lines = 23;
  341.     VSIw->linest = VSInewlinearray(VSIw->lines + 1);
  342.     VSIw->attrst = VSInewlinearray(VSIw->lines + 1);
  343.     VSIw->prredirect = 0;                        /* LU */
  344.     VSIw->prbuf = 0;                            /* LU */
  345.     VSIw->refNum = -1;                            /* LU */
  346.     VSinuse++;
  347.  
  348.     if (VSscreens[VSIwn].stat == 2)
  349.       {
  350.         VSscreens[VSIwn].stat = 1;
  351.         VSIclrbuf();
  352.         VSItabinit();
  353.         return(VSIwn);
  354.       } /* if */
  355.     VSscreens[VSIwn].stat = 1;
  356.  
  357.     VSIw->tabs = (char *) NewPtr(132);        /* NCSA: SB - allow 132 column mode */
  358.     
  359. /*
  360. *  Fill initial scrollback buffer and screen storage space.
  361. *
  362. *  Memory allocation rules:
  363. *  line->mem == 0 if not a memory allocation, line->mem == 1 if it is the first
  364. *     VSline in a block (indeterminate size, may be size == 1)
  365. *  
  366. *  attributes array is ALWAYS allocated as one block.  Internally represented and
  367. *  manipulated as a linked list of lines, but only one of the lines will have 
  368. *  line->mem == 1.  This list is always supposed to be circular (it is never
  369. *  extended, as attributes are never scrolled back).
  370. *
  371. *  scrollback and screen line buffer space is allocated in large blocks.  Each
  372. *  block will have line->mem == 1 if the pointer to that VSline is "free"able.
  373. *  This list will either be circular (which means it has reached its full size),
  374. *  or it will have a NULL next field at the end.  During scrolling, the end may
  375. *  be augmented until VSIw->numlines > VSIw->maxlines or we run out of memory.
  376. *  Typically allocate memory 100 lines at a time in two blocks, one is the VSline
  377. *  list, the other is the mem for the character storage.
  378. *
  379. */
  380.     if (screensave)
  381.         tt = VSInewlines(VSIw->lines + 1 + VSDEFLINES); /* screen lines plus some initial preallocated scrollback space */
  382.     else
  383.         tt = VSInewlines(VSIw->lines + 1); /* screen lines, no scrollback */
  384.     if (!tt)
  385.         return(-2);
  386.     VSIw->buftop = tt;
  387.     VSIw->scrntop = VSIw->buftop;    
  388.     
  389.     tt = VSInewlines(VSIw->lines + 1);        /* new space for attributes (these are never scrolled back) */
  390.     if (!tt)
  391.         return(-2);
  392.     VSIw->attrst[0] = tt;
  393.     VSIlistndx(VSIw->scrntop, VSIw->attrst[0]);    /* Set up screen arrays */
  394.     VSIw->attrst[0]->prev = VSIw->attrst[VSIw->lines]; /* make attribute list circular, since it is never extended */
  395.     VSIw->attrst[VSIw->lines]->next = VSIw->attrst[0];
  396.     if (!screensave)
  397.       {
  398.       /* make text line list circular to indicate no extensions */
  399.         VSIw->linest[0]->prev = VSIw->linest[VSIw->lines];
  400.         VSIw->linest[VSIw->lines]->next = VSIw->linest[0];
  401.       } /* if */
  402.     VSIclrbuf();
  403.     VSItabinit();
  404.     VSIw->vistop = VSIw->scrntop; /* initial view = screen */
  405. #ifdef    DEBUGPC
  406.     VSckconsist(1, 1);
  407. #endif    DEBUGPC
  408.     return(VSIwn);
  409.   } /* VSnewscreen */
  410.  
  411. short VSdestroy(short w) /* screen number */
  412.   /* gets rid of a virtual screen. */
  413.   {
  414.     if (VSvalids(w) != 0)
  415.         return(-3);
  416.     VSIfreelines();
  417.     VSIfreelinelist(VSIw->attrst[0]);
  418.     DisposPtr((Ptr) VSIw->attrst);
  419.     DisposPtr((Ptr) VSIw->linest);
  420.     DisposPtr(VSIw->tabs);
  421.     DisposPtr((Ptr) VSIw);
  422.     VSscreens[w].stat = 0;
  423.     VSIwn = -1;
  424.     VSinuse--;            /* SCA '87 */
  425.     return(0);
  426.   } /* VSdestroy */
  427.  
  428. #ifdef DEBUGPC
  429. int VSckconsist(int out, int verbose)
  430. {
  431.     VSlinePtr topa, topt, a, t;
  432.     short line, i;
  433.  
  434.     for (i=0; i<VSmax; i++) {                /* For all possible screens... */
  435.         switch( VSscreens[i].stat) {
  436.         case 0:
  437.             if (out && verbose) printf("Screen %d inactive\015",i);    /* BYU 2.4.18 - changed \n to \015 */
  438.             break;
  439.         case 1:
  440.             if (out) printf("Screen %d active\015",i);    /* BYU 2.4.18 - changed \n to \015 */
  441.             VSvalids(i);
  442.  
  443.             topa=VSIw->attrst[ 0]->prev; topt=VSIw->linest[ 0]->prev;
  444.             a = VSIw->attrst[0]->next;  t= VSIw->linest[0]->next;
  445.             
  446.             if (topa && out) printf("  Attrib thinks its circular\015");    /* BYU 2.4.18 - changed \n to \015 */
  447.             if (topa != VSIw->attrst[VSIw->lines])
  448.                                 printf("***********BUT IT'S NOT*************\015");    /* BYU 2.4.18 - changed \n to \015 */
  449.             for (line=1; line<=VSIw->lines; line++) {
  450.                 if (a != VSIw->attrst[ line])  {
  451.                     if (out) printf("    Attrib line %d is wrong !\015", line);    /* BYU 2.4.18 - changed \n to \015 */
  452.                     else return(-1);
  453.                     }
  454.                 a = a->next;
  455.                 if ( !a) {
  456.                     if (out) printf("    Attrib line %d is NULL\015", line);    /* BYU 2.4.18 - changed \n to \015 */
  457.                     else if (!out && line!=VSIw->lines) return(-2);
  458.                     }
  459.                 }
  460.  
  461.             if (topt && out) printf("  Linest thinks its circular\015");    /* BYU 2.4.18 - changed \n to \015 */
  462.             if (VSIw->linest[VSIw->lines]->next) printf(" More than VSIw->lines lines.... \015");    /* BYU 2.4.18 - changed \n to \015 */
  463.             for (line=1; line<=VSIw->lines; line++) {
  464.                 if (t != VSIw->linest[ line])  {
  465.                     if (out) printf("    Linest line %d is wrong !\015", line);    /* BYU 2.4.18 - changed \n to \015 */
  466.                     else  return (-3);
  467.                     }
  468.                 t = t->next;
  469.                 if ( !t) {
  470.                     if (out) printf("    Linest line %d is NULL\015", line);    /* BYU 2.4.18 - changed \n to \015 */
  471.                     else if (line!=VSIw->lines) return(-4);
  472.                     }
  473.                 }
  474.             if (VSIw->numlines >0) {
  475.                 if (out)
  476.                     printf("    Thinks that there is scrollback of %d lines ", VSIw->numlines);
  477.                 t= VSIw->linest[VSIw->lines]->next;
  478.                 line=0;
  479.                 while ( t!=0L && t!=VSIw->buftop) {
  480.                     t=t->next;
  481.                     line++;
  482.                     }
  483.                 if (out) printf("    [ Actual is %d ]\015", line);    /* BYU 2.4.18 - changed \n to \015 */
  484.                 if (out && t==0L) printf("    Lines end in a null\015");    /* BYU 2.4.18 - changed \n to \015 */
  485.                 if (out && t==VSIw->buftop) printf("    Lines end in a wraparound\015");    /* BYU 2.4.18 - changed \n to \015 */
  486.                 }
  487.             else if (out) printf("    There is no scrollback");
  488.             break;
  489.         case 2:
  490.             if (out && verbose) printf("Screen %d detached\015",i);    /* BYU 2.4.18 - changed \n to \015 */
  491.             break;
  492.         default:
  493.             if (out) printf("Screen %d invalid stat\015",i);    /* BYU 2.4.18 - changed \n to \015 */
  494.             break;
  495.         }
  496.     }
  497.     return(0);
  498. }
  499. #endif DEBUGPC
  500.  
  501.  
  502. #ifdef USEDETACH
  503. void VSdetach(short w)
  504. {
  505.     if (VSscreens[w].captureRN)                                    /* BYU 2.4.18 */
  506.         FSClose(VSscreens[w].captureRN);                        /* BYU 2.4.18 */
  507.     if (VSscreens[w].stat!=1) return(-1);
  508.     VSscreens[w].stat=2;
  509.     VSIwn = -1;
  510.     VSinuse--;            /* SCA '87 */
  511. }
  512. #else
  513.  
  514. void VSdetach
  515.   (
  516.     short w
  517.   )
  518.   /* this version doesn't try to keep the screen storage for reuse. */
  519.   {
  520.     VSdestroy(w);
  521.   } /* VSdetach */
  522.  
  523. #endif 
  524.  
  525. short VSredraw
  526.   (
  527.     short w, /* window to redraw */
  528.     short x1, /* bounds of area to redraw, relative to visible region */
  529.     short y1,
  530.     short x2,
  531.     short y2
  532.   )
  533.   /* redisplays the specified portion of a virtual screen. */
  534.   {
  535.     char *pt, *pa;
  536.     short cc, cm;
  537.     char lc, la;
  538.     register VSlinePtr yp;
  539.     register short y;
  540.     short ox, tx1, tx2, ty1, ty2, tn = -1, offset;
  541.  
  542.     if (VSvalids(w) != 0)
  543.         return(-3);
  544.     VSIcuroff(w); /* temporarily hide cursor */
  545.  
  546.     x1 += VSIw->Rleft; x2 += VSIw->Rleft;    /* Make local coords global again */
  547.     y1 += VSIw->Rtop;  y2 += VSIw->Rtop;
  548.  
  549.     if (x2 < 0)
  550.         x2 = 0;
  551.     if (x1 < 0)
  552.         x1 = 0;
  553.     if (x2 > VSIw->maxwidth)
  554.         x2 = VSIw->maxwidth;
  555.     if (x1 > VSIw->maxwidth)
  556.         x1 = VSIw->maxwidth;
  557.     if (y2 < -VSIw->numlines)
  558.         y2 = -VSIw->numlines;    /* limit to amount of scrollback */
  559.     if (y1 < -VSIw->numlines)
  560.         y1 = -VSIw->numlines;
  561.     if (y2 > VSIw->lines)
  562.         y2 = VSIw->lines;
  563.     if (y1 > VSIw->lines)
  564.         y1 = VSIw->lines;
  565.  
  566.     tx1 = x1; tx2 = x2; ty1 = y1; ty2 = y2; /* Set up to clip redraw area to visible area */
  567.     if (!VSIclip(&tx1, &ty1, &tx2, &ty2, &tn, &offset))
  568.         RSerase(w, tx1, ty1, tx2, ty2);        /* Erase the offending area */
  569.  
  570.   /* draw visible part of scrollback buffer */
  571.     if (y1 < 0)
  572.       {
  573.         yp = VSIw->vistop;
  574.         y = y1 - VSIw->Rtop;
  575.         while (y-- > 0)
  576.             yp = yp->next;    /* Get pointer to top line we need */
  577.       } /* if */
  578.     y = y1;
  579.     while ((y < 0) && (y <= y2))
  580.       {
  581.         ox = tx1 = x1; tx2 = x2; ty1 = ty2 = y; tn = -1;
  582.         if (!VSIclip(&tx1, &ty1, &tx2, &ty2, &tn, &offset))
  583.             RSdraw(w, tx1, ty1, 0, tn, &yp->text[ox + offset]);
  584.         yp = yp->next;
  585.         y++;
  586.       } /* while */
  587.   /* draw visible part of on-screen buffer, taking account of attributes */
  588.     while (y <= y2)
  589.       {
  590.         pt = &VSIw->linest[y]->text[x2]; /* text pointer */
  591.         pa = &VSIw->attrst[y]->text[x2]; /* attribute pointer */
  592.         cm = x2; /* start of a run of characters */
  593.         cc = 1; /* length of the run */
  594.         lc = *pt; /* the last character examined */
  595.         la = *pa; /* the attributes of the last character examined */
  596.         while (cm >= x1)
  597.           {
  598.             if ((lc == ' ') && (la == 0))
  599.               {
  600.               /* skip blank areas of the screen (runs of spaces with no attributes) */
  601.                 while((cm > x1) && (*(pt - 1) == ' ') && (*(pa - 1) == 0))
  602.                   {
  603.                     pa--;
  604.                     pt--;
  605.                     cm--;
  606.                     cc++;
  607.                   } /* while */
  608.                 pa--;
  609.                 pt--;
  610.                 cm--;
  611.                 cc = 1;
  612.                 lc = *pt;
  613.                 la = *pa;
  614.                 continue;
  615.               } /* if */
  616.           /* find a run of characters with the same attributes */
  617.             while((cm > x1) && (la == *(pa - 1)))
  618.               {
  619.                 pa--;
  620.                 pt--;
  621.                 cm--;
  622.                 cc++;
  623.               } /* while */
  624.             if (cm >= x1)
  625.               /* draw the run */
  626.                 VSIdraw(w, cm, y, la, cc, pt);
  627.             pa--;
  628.             pt--;
  629.             cm--;
  630.             cc = 1;
  631.             lc = *pt;
  632.             la = *pa;
  633.           } /* while */
  634.         y++;
  635.       } /* while */
  636.     VSIcurson(w, VSIw->x, VSIw->y, 0); /* restore cursor at original position */
  637.  
  638.     tx1 = ty1 = 0;
  639.     tn = 132;
  640.     if (!VSIclip(&tx1, &ty1, &tx2, &ty2, &tn, &offset))
  641.         RSdrawsep(w, ty1, 1);                    /* Draw Separator */
  642.  
  643.     return(0);
  644.   } /* VSredraw */
  645.  
  646. short VSwrite
  647.   (
  648.     short w, /* screen to draw into */
  649.     char *ptr, /* pointer to text string */
  650.     short len  /* length of text string */
  651.   )
  652.   /* sends a stream of characters to the specified window. */
  653.   {
  654. //      _profile = 1;
  655.     if (VSvalids(w) != 0)
  656.         return(-3);
  657.     VSIcuroff(w); /* hide cursor momentarily */
  658.     VSem((unsigned char *) ptr, len);    /* BYU LSC - interpret the character stream */
  659.     VSIcurson(w, VSIw->x, VSIw->y, 1); /* restore cursor, force it to be visible. */
  660. //    _profile = 0;
  661.     return(0);
  662.   } /* VSwrite */
  663.  
  664. short VSclear(short w)
  665.   /* clears the screen and homes the cursor. Not used. */
  666.   {
  667.     if (VSvalids(w) != 0)
  668.         return(-3);
  669.     VSIes(); /* clear screen */
  670.     VSIw->x = VSIw->y = 0; /* home cursor */
  671.     VSIcurson(w, VSIw->x, VSIw->y, 1); /* Force Move */
  672.     return(0);
  673.   } /* VSclear */
  674.  
  675.  
  676.  
  677.  
  678.                                                             // MAT--We need to define how big the Queue is
  679.                                                             // MAT--for sending the cursor characters.
  680.                                                             // MAT--Since MacTCP doesn't like 30+ individual
  681. #define MATSbufSize    254                                        // MAT--SendChar requests.
  682. void VSpossendEM                                            // MAT--we can change this to support EMACS
  683.   (                                                            // MAT--style movement commands.
  684.     short w, /* affected screen */                                                // MAT--
  685.     short x, /* column to move to */                                                // MAT--
  686.     short y, /* line to move to */                                                // MAT--
  687.     short echo /* local echo flag */                                                // MAT--
  688.   )                                                                                // MAT--
  689.   /* sends a stream of VT100 cursor-movement sequences to move the                // MAT--
  690.     cursor on the specified screen to the specified position. */                // MAT--
  691. {                                                                                // MAT--
  692.     #pragma unused (echo)
  693.     static char                                                                    // MAT--
  694.             tt[MATSbufSize] = "";                                                // MAT--
  695.         char curschar;                                                            // MAT--
  696.         short localCount;                                                            // MAT--
  697.                                                                                 // MAT--
  698. //    if (VSvalids(w) != 0)            already checked for us in VSpossend            // MAT--
  699. //        return;                                                                    // MAT--
  700.                                                                                 // MAT--
  701. //    if (VSIw->DECPAM && VSIw->DECCKM)          what is this for???                    // MAT--
  702. //        vskptr = VSkbax;                                                        // MAT--
  703. //    else                                                                        // MAT--
  704. //        vskptr = VSkban;                                                        // MAT--
  705.                                                                                 // MAT--
  706.     if (x < 0 || y < 0 || x > VSIw->maxwidth || y > VSIw->lines)                // MAT--
  707.         return;                                                                    // MAT--
  708.   /* convert x and y to relative distance to move */                            // MAT--
  709.     x -= VSIw->x;                                                                // MAT--
  710.     y -= VSIw->y;                                                                // MAT--
  711.                                                                                 // MAT--
  712.     curschar = '\002'; /* EMACS cursor left */                                    // MAT--
  713.     localCount=0;
  714.     while (x < 0 && localCount < MATSbufSize)                                    // MAT--
  715.       {                                                                            // MAT--
  716.         tt[localCount] = curschar;                                                // MAT--
  717.         x++; localCount++;                                                        // MAT--
  718.       } /* while */                                                                // MAT--
  719.     if(localCount)    RSsendstring(w, tt, localCount);                            // MAT--
  720.  
  721.     curschar = '\016'; /* EMACS cursor down */                                    // MAT--
  722.     localCount=0;
  723.     while (y > 0 && localCount < MATSbufSize)                                    // MAT-- why we check to see if localCount is < MATSbufSize
  724.       {                                                                            // MAT-- I dont know. But If they had a window > 254 columns
  725.         tt[localCount] = curschar;                                                // MAT-- maybe it's a good idea.
  726.         y--; localCount++;                                                        // MAT-- but it never hurts to be safe.
  727.       } /* while */                                                                // MAT--
  728.     if(localCount)    RSsendstring(w, tt, localCount);                            // MAT--
  729.  
  730.     curschar = '\020'; /* EMACS cursor up */                                    // MAT--
  731.     localCount=0;
  732.     while (y < 0 && localCount < MATSbufSize)                                    // MAT--
  733.       {                                                                            // MAT--
  734.         tt[localCount] = curschar;                                                // MAT--
  735.         y++; localCount++;                                                        // MAT--
  736.       } /* while */                                                                // MAT--
  737.     if(localCount)    RSsendstring(w, tt, localCount);                            // MAT--
  738.  
  739.     curschar = '\006'; /* EMACS cursor right */                                    // MAT--
  740.     localCount=0;
  741.     while (x > 0 && localCount < MATSbufSize)                                    // MAT--
  742.       {                                                                            // MAT--
  743.         tt[localCount] = curschar;                                                // MAT--
  744.         x--; localCount++;                                                        // MAT--
  745.       } /* while */                                                                // MAT--
  746.     if(localCount)    RSsendstring(w, tt, localCount);                            // MAT--
  747.                                                                                 // MAT--
  748.     if (0)    //(note: supposed to look for "echo" here)                            // MAT--
  749.       {                                                                            // MAT--
  750.         VSIcuroff(w);                                                            // MAT--
  751.         VSIw->x = x;                                                            // MAT--
  752.         VSIw->y = y;                                                            // MAT--
  753.         VSIcurson(w, VSIw->x, VSIw->y, 1); /* Force Move */                        // MAT--
  754.       } /* if */                                                                // MAT--
  755.   } /* VSpossendEM */                    // changed comment                        // MAT--
  756.      
  757. void VSpossend
  758.   (
  759.     short w, /* affected screen */
  760.     short x, /* column to move to */
  761.     short y, /* line to move to */
  762.     short echo /* local echo flag */
  763.   )
  764.   /* sends a stream of VT100 cursor-movement sequences to move the
  765.     cursor on the specified screen to the specified position. */
  766. {
  767.     static char
  768.         VSkbax[] = "\033O ",        /* prefix for auxiliary code */
  769.         VSkban[] = "\033[ ";        /* prefix for arrows normal */
  770.     char *vskptr;
  771.  
  772.     if (VSvalids(w) != 0)
  773.         return;
  774.     
  775.     
  776. /* NCSA: SB - This would bomb before.  You need to get the screens # from the 
  777.                 translation routine before you access the record! */      
  778.     if (screens[findbyVS(w)].arrowmap) {    /* NCSA: SB - get the CORRECT screens # */
  779.         VSpossendEM(w,x,y,echo);            // MAT--  call our cursor movement routine
  780.         return;                             // MAT--  then exit
  781.     }
  782.  
  783.     if (VSIw->DECPAM && VSIw->DECCKM)
  784.         vskptr = VSkbax;
  785.     else
  786.         vskptr = VSkban;
  787.     if (x < 0 || y < 0 || x > VSIw->maxwidth || y > VSIw->lines)
  788.         return;
  789.   /* convert x and y to relative distance to move */
  790.     x -= VSIw->x;
  791.     y -= VSIw->y;
  792.  
  793.     vskptr[2] = 'D'; /* cursor left */
  794.     while (x < 0)
  795.       {
  796.         x++;
  797.         RSsendstring(w, vskptr, 3);
  798.       } /* while */
  799.  
  800.     vskptr[2] = 'B'; /* cursor down */
  801.     while (y > 0)
  802.       {
  803.         y--;
  804.         RSsendstring(w, vskptr, 3);
  805.       } /* while */
  806.     vskptr[2] = 'A'; /* cursor up */
  807.     while (y < 0)
  808.       {
  809.         y++;
  810.         RSsendstring(w, vskptr, 3);
  811.       } /* while */
  812.     vskptr[2] = 'C'; /* cursor right */
  813.     while (x > 0)
  814.       {
  815.         x--;
  816.         RSsendstring(w, vskptr, 3);
  817.       } /* while */
  818.  
  819.     if (echo)
  820.       {
  821.         VSIcuroff(w);
  822.         VSIw->x = x;
  823.         VSIw->y = y;
  824.         VSIcurson(w, VSIw->x, VSIw->y, 1); /* Force Move */
  825.       } /* if */
  826.   } /* VSpossend */
  827.  
  828. char VSkbsend
  829.   (
  830.     short w, /* active window */
  831.     unsigned char k, /* special key code if > 128, else ascii code */
  832.     short echo /* local echo flag */
  833.   )
  834.   /* sends the appropriate sequence for the specified key, taking due
  835.     account of terminal mode settings. */
  836.   {
  837.     static char
  838.         VSkbkn[] = "\033O ",        /* prefix for keypad normal */
  839.         VSkbax[] = "\033O ",        /* prefix for auxiliary code*/
  840.         VSkban[] = "\033[ ",        /* prefix for arrows normal */
  841.         VSkbfn[] = "\033O ",        /* prefix for function keys */        /* BYU 2.4.12 */
  842.         VSk220[] = "\033[  ~";        /* prefix for vt220 keys */            /* BYU 2.4.12 */
  843.     char *vskptr;
  844.     short vskplen;
  845.  
  846.  
  847.     if (VSvalids(w) != 0)
  848.         return(-3);
  849.  
  850.     if ( screens[findbyVS(w)].arrowmap && (k <= VSLT) && (k >= VSUP) )    // MAT--
  851.                                         // MAT-- important...we need to check this first before
  852.         {                                // MAT-- the next if(…) statement gets its hands on the string.
  853.             switch (k) {                // MAT--  do the mapping from arrowkeys -> EMACS ctrl keys.
  854.                 case VSLT:                // MAT-- 
  855.                     k = 0x02;            // MAT-- ^B            Question: Is there a way to find out if the option
  856.                     break;                // MAT--                       key was held down with this character?
  857.                 case VSRT:                // MAT--             I didn't want to declare myEvent an extern
  858.                     k = 0x06;            // MAT-- ^F            (I didn't know if that was a no-no)
  859.                     break;                // MAT--             If I can.....let me know, I want to make
  860.                 case VSUP:                // MAT--             option-arrowkey's do useful things too
  861.                     k = 0x10;            // MAT-- ^P
  862.                     break;                // MAT--             checking the keymap would be a kludge here.
  863.                 case VSDN:                // MAT-- 
  864.                     k = 0x0e;            // MAT-- ^N
  865.                     break;                // MAT-- 
  866.             }    /* switch k */            // MAT--
  867.             RSsendstring(w,(char *)&k,1);        // MAT-- send the character
  868.             return(0);                    // MAT--
  869.         }                                // MAT--
  870.  
  871.  
  872.     if (k < VSF10)                            /* BYU 2.4.12 */
  873.       /* 7-bit ascii code -- send as is */
  874.         RSsendstring(w,(char *) &k, 1);        /* BYU LSC */
  875.     
  876.     /* Keypad (Not Application Mode): 0-9 , - . Enter */    
  877.     if ((k > VSLT) && (k < VSF1) && (!VSIw->DECPAM)) {
  878.         RSsendstring(w, &VSIkpxlate[0][k - VSUP], 1);
  879.         if (echo)
  880.             VSwrite(w, &VSIkpxlate[0][k - VSUP], 1);
  881.         if (k == VSKE)
  882.             RSsendstring(w, "\012", 1);
  883.         return(0);
  884.       } /* if */
  885.     
  886.       
  887.     if (VSIw->DECPAM && VSIw->DECCKM) {
  888.       /* aux kp mode */
  889.           vskptr = VSkbax;
  890.         vskplen = 3;
  891.         vskptr[2] = VSIkpxlate[1][k - VSUP];    /* BYU 2.4.12 */
  892.       }
  893.     else if (k < VSUP) {                        /* BYU 2.4.12 */
  894.         vskptr = VSk220;                        /* BYU 2.4.12 */
  895.         vskplen = VSIkplen[k - VSF10];            /* BYU 2.4.12 */
  896.         vskptr[2] = VSIkpxlate2[k - VSF10];        /* BYU 2.4.12 */
  897.         vskptr[3] = VSIkpxlate3[k - VSF10];        /* BYU 2.4.12 */
  898.     } else {                                    /* BYU 2.4.12 */
  899.         vskplen = 3;                            /* BYU 2.4.12 */
  900.         if (k < VSK0) {                            /* BYU 2.4.13 - arrow keys */
  901.             vskptr = VSkban;                    /* BYU 2.4.12 */
  902.             if (VSIw->DECCKM)                    /* BYU 2.4.13 */
  903.                 vskptr[1] = 79;                    /* BYU 2.4.13 */
  904.             else                                /* BYU 2.4.13 */
  905.                 vskptr[1] = 91;                    /* BYU 2.4.13 */
  906.         }                                        /* BYU 2.4.13 */
  907.         else if (k < VSF1)                         /* BYU 2.4.12 */
  908.             vskptr = VSkbkn;                    /* BYU 2.4.12 */
  909.         else                                     /* BYU 2.4.12 */
  910.             vskptr = VSkbfn;                    /* BYU 2.4.12 */
  911.                                                 /* BYU 2.4.12 */
  912.         vskptr[2] = VSIkpxlate[1][k - VSUP];    /* BYU 2.4.12 */
  913.     }                                            /* BYU 2.4.12 */
  914.  
  915.     RSsendstring(w, vskptr, vskplen);
  916.     if (echo)
  917.         VSwrite(w, vskptr, vskplen);
  918.     return(0);
  919.   } /* VSkbsend */
  920.  
  921. short VSclearall(short w)
  922.   /* doesn't seem to do anything interesting. Not used. */
  923.   {
  924.     if (VSvalids(w) != 0)
  925.         return(-3);
  926.     return(0);
  927.   } /* VSclearall */
  928.  
  929. short VSreset
  930.   (
  931.     short w
  932.   )
  933.   /* resets virtual terminal settings to default state, clears screen
  934.     and homes cursor. */
  935.   {
  936.     if (VSvalids(w) != 0)
  937.         return(-3);
  938.     VSIcuroff(w);            /* NCSA: SB -- get rid of extraneous cursor BS */
  939.     VSIreset(); /* causes cursor to disappear */
  940.     VSIcurson(w, VSIw->x, VSIw->y, 1); /* redisplay cursor at home position */
  941.     return(0);
  942.   } /* VSreset */
  943.  
  944. char *VSgetline(short w, short y)
  945.   /* returns a pointer to the text for the specified on-screen line.
  946.     Doesn't work for negative values of y (i e lines in the
  947.     scrollback area). Not used. */
  948.   {
  949.     if (VSvalids(w) != 0)
  950.         return((char *) -3);
  951.     return(VSIw->linest[y]->text);
  952.   } /* VSgetline */
  953.  
  954. void VSscrolright
  955.   (
  956.     short w,
  957.     short n /* number of columns to scroll */
  958.   )
  959.   /* moves the view of the virtual screen within its window the
  960.     specified number of columns to the right. */
  961.   {
  962.     short sn, lmmax;
  963.  
  964.     if (VSvalids(w) != 0)
  965.         return;
  966.  
  967.   /* limit scroll amount against number of invisible columns */
  968.     lmmax = VSIw->maxwidth - (VSIw->Rright - VSIw->Rleft);
  969.     if (VSIw->Rleft + n > lmmax)
  970.         n = lmmax - VSIw->Rleft; /* can't scroll any further right than this */
  971.     if (n == 0)
  972.         return;                                    /* Do nothing if appropriate */
  973.  
  974.     VSIcuroff(w); /* temporarily hide cursor */
  975.     VSIw->Rleft += n; /* update visible region */
  976.     VSIw->Rright += n;
  977.     sn = VSIw->Rbottom - VSIw->Rtop;
  978.     RSmargininfo(w, lmmax, VSIw->Rleft);    /* update horizontal scroll bar */
  979.     RSdelcols(w, n); /* scroll the window contents */
  980.     VSIcurson(w, VSIw->x, VSIw->y, 0); /* restore cursor at original position */
  981.   /* redraw newly-revealed portion of screen */
  982.     VSredraw(w, (VSIw->Rright - VSIw->Rleft) - n, 0, (VSIw->Rright - VSIw->Rleft), sn);
  983.   } /* VSscrolright */
  984.  
  985. void VSscrolleft
  986.   (
  987.     short w,
  988.     short n /* number of columns to scroll */
  989.   )
  990.   /* moves the view of the virtual screen within its window the
  991.     specified number of columns to the left. */
  992.   {
  993.     short sn, lmmax;
  994.  
  995.     if (VSvalids(w) != 0)
  996.         return;
  997.  
  998.     lmmax = VSIw->maxwidth - (VSIw->Rright - VSIw->Rleft); /* number of invisible columns */
  999.  
  1000.     if (n > VSIw->Rleft)
  1001.         n = VSIw->Rleft; /* can't scroll any further left than this */
  1002.     if (n == 0)
  1003.         return;                                    /* Do nothing if appropriate */
  1004.  
  1005.     VSIcuroff(w); /* temporarily hide cursor */
  1006.     VSIw->Rleft -= n; /* update visible region */
  1007.     VSIw->Rright -= n;
  1008.     sn = VSIw->Rbottom - VSIw->Rtop;
  1009.     RSmargininfo(w, lmmax, VSIw->Rleft); /* update horizontal scroll bar */
  1010.     RSinscols(w, n); /* scroll the window contents */
  1011.     VSIcurson(w, VSIw->x, VSIw->y, 0); /* restore cursor at original position */
  1012.     VSredraw(w, 0, 0, n, sn); /* redraw newly-revealed portion of screen */
  1013.   } /* VSscrolleft */
  1014.  
  1015. short VSscroltop( short w /* which window */)                    /* JMB 2.6 */
  1016. {                                                            /* JMB 2.6 */
  1017.     if (VSvalids(w) != 0)                                    /* JMB 2.6 */
  1018.         return(-3);                                            /* JMB 2.6 */
  1019.                                                             /* JMB 2.6 */
  1020.     return(VSscrolback(w, VSIw->Rtop + VSIw->numlines)); /* can't scroll back any further than this */
  1021. }                                                            /* JMB 2.6 */
  1022.  
  1023. short VSscrolback
  1024.   (
  1025.     short w, /* which window */
  1026.     short in /* number of lines to scroll */
  1027.   )
  1028.   /* moves the view of the virtual screen within its window the
  1029.     specified number of lines upwards. */
  1030.   {
  1031.     short sn, n;
  1032.  
  1033.     n = in;
  1034.  
  1035.     if (VSvalids(w) != 0)
  1036.         return(-3);
  1037.  
  1038.     if (VSIw->numlines < (n - VSIw->Rtop))
  1039.         n = VSIw->Rtop + VSIw->numlines; /* can't scroll back any further than this */
  1040.     if (n <= 0)
  1041.         return(0);            /* Dont be scrollin' no lines.... */
  1042.  
  1043.     VSIcuroff(w); /* temporarily hide cursor */
  1044.  
  1045.     VSIw->Rtop = VSIw->Rtop - n; /* adjust the visible region */
  1046.     VSIw->Rbottom = VSIw->Rbottom - n;
  1047.  
  1048.   /* find the line list element for the new topmost visible line */
  1049.     sn = n;
  1050.     while (sn-- > 0)
  1051.       {
  1052. #ifdef DEBUGMAC
  1053.         if (VSIw->vistop->prev == 0L)
  1054.             DebugStr("\pVSscrolback -- something wrong with linked list structure");
  1055. #endif DEBUGMAC
  1056.         VSIw->vistop = VSIw->vistop->prev;
  1057.       } /* while */
  1058.  
  1059.     sn = VSIw->Rbottom - VSIw->Rtop;
  1060.   /* update vertical scroll bar */
  1061.     RSbufinfo(w, VSIw->numlines, VSIw->Rtop, VSIw->Rbottom);
  1062.  
  1063.     if (n <= VSIw->lines)
  1064.       {
  1065.         RSinslines(w, 0, sn, n, 0);    /* scroll, preserving current selection */
  1066.         VSIcurson(w, VSIw->x, VSIw->y, 0); /* restore cursor at original position */
  1067.         VSredraw(w, 0, 0, VSIw->maxwidth, n - 1); /* redraw newly-revealed portion */
  1068.       }
  1069.     else
  1070.       /* currently-visible contents scrolled completely off the screen--
  1071.         just redraw everything */
  1072.         VSredraw(w, 0, 0, VSIw->maxwidth, sn);
  1073.  
  1074.     return(0);
  1075.   } /* VSscrolback */
  1076.  
  1077. short VSscrolforward
  1078.   (
  1079.     short w, /* which window */
  1080.     short n /* number of lines to scroll */
  1081.   )
  1082.   /* moves the view of the virtual screen within its window the
  1083.     specified number of lines downwards. */
  1084.   {
  1085.     short sn;
  1086.  
  1087.     if (VSvalids(w) != 0)
  1088.         return(-3);
  1089.  
  1090.     if (n > VSIw->lines - VSIw->Rbottom)
  1091.         n = VSIw->lines - VSIw->Rbottom; /* can't scroll any further forward than this */
  1092.     if (n <= 0)
  1093.         return(0);            /* Dont be scrollin' no lines.... */
  1094.  
  1095.     VSIcuroff(w); /* temporarily hide cursor */
  1096.  
  1097.     VSIw->Rtop = n + VSIw->Rtop; /* adjust the visible region */
  1098.     VSIw->Rbottom = n + VSIw->Rbottom;
  1099.  
  1100.   /* find the line list element for the new topmost visible line */
  1101.     sn = n;
  1102.     while (sn-- > 0)
  1103.       {
  1104. #ifdef DEBUGMAC
  1105.         if (VSIw->vistop->next == nil)
  1106.             DebugStr("\pVSscrolforward -- something wrong with linked list structure");
  1107. #endif DEBUGMAC
  1108.         VSIw->vistop = VSIw->vistop->next;
  1109.       } /* while */
  1110.  
  1111.     sn = VSIw->Rbottom - VSIw->Rtop;
  1112.   /* update vertical scroll bar */
  1113.     RSbufinfo(w, VSIw->numlines, VSIw->Rtop, VSIw->Rbottom);
  1114.  
  1115.     if (n <= VSIw->lines)
  1116.       {
  1117.         RSdellines(w, 0, sn, n, 0);    /* scroll, preserving current selection */
  1118.         VSIcurson(w, VSIw->x, VSIw->y, 0); /* restore cursor at original position */
  1119.         VSredraw(w, 0, (sn + 1) - n, VSIw->maxwidth, sn); /* redraw newly-revealed portion */
  1120.       } /* if */
  1121.     else
  1122.       /* currently-visible contents scrolled completely off the screen--
  1123.         just redraw everything */
  1124.         VSredraw(w, 0, 0, VSIw->maxwidth, sn);
  1125.  
  1126.     return(0);
  1127.   } /* VSscrolforward */
  1128.  
  1129. short VSsetrgn
  1130.   (
  1131.     short w,
  1132.     short x1, /* leftmost column */
  1133.     short y1, /* uppermost line */
  1134.     short x2, /* rightmost column */
  1135.     short y2 /* bottommost line */
  1136.   )
  1137.   /* sets the visible region for the specified virtual screen
  1138.     in its window, scrolling its contents as appropriate. Assumes
  1139.     that either the vertical bounds or the height of the region has
  1140.     changed, but not both, and similarly that the horizontal bounds
  1141.     or the width has changed, but not both. */
  1142.   {
  1143.     short n, offset;
  1144.  
  1145.     if (VSvalids(w) != 0)
  1146.         return(-3);
  1147.  
  1148.     VSIw->Rbottom = VSIw->Rtop + (y2 - y1); /* make change in height of visible region first */
  1149.  
  1150.     if (x2 > VSIw->maxwidth)
  1151.       {
  1152.       /* trying to make columns visible which aren't there--
  1153.         adjust the left and right boundaries to avoid this */
  1154.         n = x2 - VSIw->maxwidth; /* how far to adjust to the left */
  1155.         if (n > x1)
  1156.             n = x1; /* but I'd rather have unused columns on the right than on the left */
  1157.         x1 -= n;                            /* Adjust left    */
  1158.         x2 -= n;                            /* Adjust right */
  1159.       } /* if */
  1160.  
  1161.     if (VSIw->Rleft != x1)
  1162.       {
  1163.       /* left margin changed -- scroll horizontally */
  1164.       /* (assume width of region hasn't also changed) */
  1165.         n = x1 - VSIw->Rleft;
  1166.         if (n > 0)
  1167.             VSscrolright(w, n);
  1168.         else
  1169.             VSscrolleft(w, -n);
  1170.       }
  1171.     else
  1172.       /* just update horizontal scroll bar limits for new width of visible region */
  1173.         RSmargininfo(w, VSIw->maxwidth - (x2 - x1), x1);
  1174.  
  1175.     VSIw->Rleft = x1;
  1176.     VSIw->Rright = x2;
  1177.  
  1178.     if (VSIw->Rbottom > VSIw->lines)
  1179.       /* don't scroll off the bottom of the screen */
  1180.         n = VSIw->Rbottom - VSIw->lines;
  1181.     else
  1182.       /* scroll to new topmost line as specified */
  1183.         n = VSIw->Rtop - y1;
  1184.  
  1185.     if (n != 0)
  1186.       /* scroll vertically (assume height of region hasn't also changed) */
  1187.         if (n > 0)
  1188.             VSscrolback(w, n);
  1189.         else
  1190.             VSscrolforward(w, -n);
  1191.     else
  1192.       {
  1193.       /* just redraw separator (if it's become visible) */
  1194.         x1 = y1 = 1;
  1195.         n = 132;
  1196.         if (!VSIclip(&x1, &y1, &x2, &y2, &n, &offset))
  1197.             RSdrawsep(w, n, 1);
  1198.       /* and update vertical scroll bar limits for new height of visible region */
  1199.         RSbufinfo(w, VSIw->numlines, VSIw->Rtop, VSIw->Rbottom);
  1200.       } /* if */
  1201.     return(0);
  1202.   } /* VSsetrgn */
  1203.  
  1204. short VSscrolcontrol
  1205.   (
  1206.     short w,
  1207.     short scrolon, /* whether to save lines off top */
  1208.     short offtop /* whether to save lines on clearing entire screen */
  1209.   )
  1210.   /* changes scrollback flag settings for a virtual screen. */
  1211.   {
  1212.     if (VSvalids(w) != 0)
  1213.         return(-3);
  1214.  
  1215.     if (scrolon > -1)
  1216.         VSIw->savelines = scrolon;
  1217.     if (offtop > -1)
  1218.         VSIw->ESscroll = offtop;
  1219.  
  1220.     return(0);
  1221.   } /* VSscrolcontrol */
  1222.  
  1223. short VSgetrgn
  1224.   (
  1225.     short w,
  1226.     short *x1,
  1227.     short *y1,
  1228.     short *x2,
  1229.     short *y2
  1230.   )
  1231.   /* returns the current visible region for a virtual screen. */
  1232.   {
  1233.     if (VSvalids(w) != 0)
  1234.         return(-3);
  1235.  
  1236.     *x1 = VSIw->Rleft;
  1237.     *y1 = VSIw->Rtop;
  1238.     *x2 = VSIw->Rright;
  1239.     *y2 = VSIw->Rbottom;
  1240.    
  1241.     return(0);
  1242.   } /* VSgetrgn */
  1243.  
  1244. short VSsnapshot(short w)
  1245.   /* does nothing interesting. Not used. */
  1246.   {
  1247.     if (VSvalids(w) != 0)
  1248.         return(-3);
  1249.     return(0);
  1250.   } /* VSsnapshot */
  1251.  
  1252. short VSmaxwidth
  1253.   (
  1254.     short w
  1255.   )
  1256.   /* returns one less than the number of columns on a virtual screen. */
  1257.   {
  1258.     if (VSvalids(w) != 0)
  1259.         return(-3);
  1260.     return(VSIw->maxwidth);
  1261.   } /* VSmaxwidth */
  1262.  
  1263. VSlinePtr VSIGetLineStart(short w, short y1)
  1264.   /* returns a pointer to the specified text line (number may be
  1265.     negative for a line in the scrollback buffer). */
  1266.   {
  1267.     VSlinePtr ptr;
  1268.     short n;
  1269.  
  1270.     if (VSvalids(w) != 0)
  1271.         return((VSlinePtr) -3);
  1272.  
  1273.     if (y1 >= 0)
  1274.         return(VSIw->linest[y1]);
  1275.  
  1276.     n = y1 - VSIw->Rtop;                /* Number of lines from VISTOP to scroll forward */
  1277.     ptr = VSIw->vistop;
  1278.     while (n > 0)
  1279.       {
  1280.         n--;
  1281.         ptr = ptr->next;
  1282.       } /* while */
  1283.     while (n < 0)
  1284.       {
  1285.         n++;
  1286.         ptr = ptr->prev;
  1287.       } /* while */
  1288.     return(ptr);
  1289.   } /* VSIGetLineStart */
  1290.  
  1291. char *VSIstrcopy(char *src, short len, char *dest, short table)
  1292.   /* copies characters from *src (length len) to *dest, dropping
  1293.     trailing blanks. If table is nonzero, then this number (or more) of
  1294.     consecutive embedded blanks will be replaced with a tab. Returns a pointer
  1295.     to the position one past the last character copied to the *dest buffer. */
  1296.   {
  1297.     char *p, *tempp;
  1298.     short tblck;
  1299.  
  1300.     p = src + len - 1;
  1301.   /* skip trailing blanks */
  1302.     while ((*p == ' ') && (p >= src))
  1303.         p--;
  1304.     if (p < src)
  1305.         return(dest);
  1306.     if (!table)
  1307.       /* straight character copy */
  1308.         while (src <= p)
  1309.             *dest++ = *src++;
  1310.     else
  1311.       /* tab-replacement copy */
  1312.         while (src <= p)
  1313.           {
  1314.             while ((src <= p) && (*src != ' '))
  1315.                 *dest++ = *src++;
  1316.             if (src < p)
  1317.               {
  1318.                 tempp = dest; /* remember start of run of spaces */
  1319.                 tblck = 0; /* length of run */
  1320.                 while ((src <= p) && (*src == ' '))
  1321.                   {
  1322.                     *dest++ = *src++;
  1323.                     tblck++;
  1324.                   } /* while */
  1325.                 if (tblck >= table)
  1326.                   {
  1327.                     *tempp++ = '\011'; /* replace first space with a tab */
  1328.                     dest = tempp; /* drop remaining spaces */
  1329.                   } /* if */
  1330.               } /* if */
  1331.           } /* while */
  1332.     return(dest);
  1333.   } /* VSIstrcopy */
  1334.  
  1335. long VSgettext(short w, short x1, short y1, short x2, short y2, char *charp, long max, char *EOLS, short table)
  1336.   /* copies a portion of text from the specified virtual screen into
  1337.     the *charp buffer. table, if nonzero, is the minimum length of
  1338.     runs of spaces to be replaced with single tabs. Returns the
  1339.     length of the copied text. max is supposed to be the maximum
  1340.     length to copy, but this is currently ignored!
  1341.     EOLS is the end-of-line sequence to insert at line boundaries.
  1342.     This is currently assumed to be exactly one character long. */
  1343.   {
  1344. #pragma unused(max) /* !! */
  1345.     short EOLlen;
  1346.     short lx,ly,                    /* Upper bounds of selection */
  1347.         ux,uy;                    /* Lower bounds of selection */
  1348.     short maxwid;
  1349.     char *origcp;
  1350.     VSlinePtr t;
  1351.  
  1352.     if (VSvalids(w) != 0)
  1353.         return(-3);
  1354.     EOLlen = strlen(EOLS);
  1355.     maxwid = VSIw->maxwidth;
  1356.     origcp = charp;
  1357.  
  1358.     if (y1 < -VSIw->numlines)
  1359.       {
  1360.         y1 = -VSIw->numlines;
  1361.         x1 = -1;
  1362.       } /* if */
  1363.     if (y1 == y2)
  1364.       {
  1365.       /* copying no more than a single line */
  1366.         t = VSIGetLineStart(w, y1);
  1367.         if (x1 < x2)    /* Order the lower and upper bounds */
  1368.           {
  1369.             ux = x1;
  1370.             uy = y1;
  1371.             lx = x2;
  1372.             ly = y2;
  1373.           }
  1374.         else
  1375.           {
  1376.             ux = x2;
  1377.             uy = y2;
  1378.             lx = x1;
  1379.             ly = y1;
  1380.           } /* if */
  1381.  
  1382.         if ((long)(lx-ux) < max)
  1383.             charp=VSIstrcopy(&t->text[ux+1], lx-ux, charp, table);
  1384.         else
  1385.             charp=VSIstrcopy(&t->text[ux+1], (short)(max - (long)(charp-origcp)), charp, table);
  1386.         if (lx == maxwid)
  1387.             *charp++ = *EOLS; /* assumes it's only one character! */
  1388.       }
  1389.     else
  1390.       {
  1391.       /* copying more than one line */
  1392.         if (y1 < y2)    /* Order the lower and upper bounds */
  1393.           {
  1394.             ux = x1;
  1395.             uy = y1;
  1396.             lx = x2;
  1397.             ly = y2;
  1398.           }
  1399.         else
  1400.           {
  1401.             ux = x2;
  1402.             uy = y2;
  1403.             lx = x1;
  1404.             ly = y1;
  1405.           } /* if */
  1406.         t = VSIGetLineStart(w, uy);
  1407.         if (((long) (maxwid-ux) < max))
  1408.             charp=VSIstrcopy(&t->text[ux+1],maxwid-ux,charp,table);
  1409.         else
  1410.             charp=VSIstrcopy(&t->text[ux+1],(short) (max-(long)(charp-origcp)),charp,table);
  1411.         *charp++ = *EOLS; /* assumes it's only one character! */
  1412.         uy++;
  1413.         t = t->next;
  1414.         while (uy < ly && uy < VSIw->lines)
  1415.           {
  1416.             if ((long)(maxwid+1) < max)
  1417.                 charp=VSIstrcopy(t->text,maxwid+1,charp, table);
  1418.             else
  1419.                  charp=VSIstrcopy(t->text,(short)(max - (long) (charp-origcp)),charp, table);
  1420.             *charp++=*EOLS;
  1421.             t=t->next; 
  1422.             uy++;
  1423.           } /* while */
  1424.         if (ly > VSIw->lines)
  1425.             lx = maxwid;
  1426.  
  1427.         if ((long) (lx+1) < max)
  1428.             charp=VSIstrcopy(t->text,lx+1,charp,table);
  1429.         else
  1430.             charp=VSIstrcopy(t->text,(short)(max - (long)(charp-origcp)),charp,table);
  1431.  
  1432.         if (lx >= maxwid)
  1433.             *charp++ = *EOLS; /* assumes it's only one character! */
  1434.       } /* if */
  1435.     return(charp - origcp);
  1436.   } /* VSgettext */
  1437.  
  1438. short VSgetlines
  1439.   (
  1440.     short w
  1441.   )
  1442.   /* returns the number of lines in a virtual screen. */
  1443.   {
  1444.     if (VSvalids(w) != 0)
  1445.         return(-3);
  1446.     return(VSIw->lines + 1);
  1447.   } /* VSgetlines */
  1448.  
  1449. short VSsetlines
  1450.   (
  1451.     short w, /* window number */
  1452.     short lines /* new number of lines */
  1453.   )
  1454.   /* sets the number of lines in a virtual screen, reallocating text
  1455.     and attribute arrays accordingly. Returns the new number of lines
  1456.     on success. */
  1457.   {
  1458.     VSlineArray attrst, linest;                /* For storage of old ones */
  1459.     VSlinePtr line;                            /* pointer to a line */
  1460.     short i, j, oldlines;
  1461.     char *temp, *tempa;
  1462.     
  1463.     if (VSvalids(w) != 0)
  1464.         return(-3);
  1465.     
  1466.     lines -= 1;                                /* Correct for internal use */
  1467.     oldlines = VSIw->lines;
  1468.     if (lines == oldlines)    
  1469.       /* no change */
  1470.         return(0);
  1471.     
  1472.     VSIw->x = 0;
  1473.     VSIw->y = 0;
  1474.     VSIcurson(w, VSIw->x, VSIw->y, 1);     /* keeps cursor from pointing outside of window */
  1475.  
  1476.   /* VSIw->scrntop = VSIw->linest[0]; */
  1477.     VSIw->vistop = VSIw->scrntop;            /* Force view to the top of the screen */
  1478.   /* VSIlistndx(VSIw->scrntop, VSIw->attrst[0]); */
  1479.     attrst = VSIw->attrst; /* save old screen arrays */
  1480.     linest = VSIw->linest;
  1481.   /* allocate new screen buffers for text and attributes */
  1482.     VSIw->linest = VSInewlinearray(lines + 1);
  1483.     if (!VSIw->linest)
  1484.       {
  1485.       /* aarrgghh -- out of memory */
  1486.         VSIw->linest = linest;
  1487.         return -2;
  1488.       } /* if */
  1489.     VSIw->attrst = VSInewlinearray(lines + 1);
  1490.     if (!VSIw->attrst)
  1491.       {
  1492.       /* aarrgghh -- out of memory */
  1493.         DisposPtr((Ptr) VSIw->linest);
  1494.         VSIw->linest = linest;
  1495.         VSIw->attrst = attrst;
  1496.         return -2;
  1497.       } /* if */
  1498.     VSIw->lines = lines; /* set new number of screen lines */
  1499.  
  1500.     VSIw->linest[0] = VSInewlines(lines + 1); /* allocate new text and attribute lines */
  1501.     VSIw->attrst[0] = VSInewlines(lines + 1);
  1502.     if (VSIw->linest[0] && VSIw->attrst[0])
  1503.       {    /* mem is there */
  1504.         VSIlistndx(VSIw->linest[0], VSIw->attrst[0]); /* build the new screen arrays */
  1505.         if (VSIw->savelines)
  1506.           {
  1507.           /* save previous screen contents in scrollback buffer */
  1508.             line = linest[oldlines]->next;                /* save continuation */
  1509.             linest[oldlines]->next = VSIw->linest[0];
  1510.             VSIw->linest[lines]->next = line;            /* restore continuation */
  1511.             VSIw->linest[0]->prev = linest[oldlines];    /* backpointer */
  1512.             if (line)                                    /* if there was a follower */
  1513.                 line->prev = VSIw->linest[lines];        /* new prev for it */
  1514.             VSIw->numlines += oldlines;                    /* we made more scrollback */
  1515.           }
  1516.         else
  1517.           /* get rid of previous screen contents */
  1518.             VSIfreelinelist(linest[0]);
  1519.       }
  1520.     else
  1521.       {                                        /* need more mem - emergency */
  1522.         if (VSIw->linest[0])
  1523.             VSIfreelinelist(VSIw->linest[0]);
  1524.         if (VSIw->attrst[0])
  1525.             VSIfreelinelist(VSIw->attrst[0]);
  1526.         VSIfreelines();                            /* release them all */
  1527.         VSIw->linest[0] = VSInewlines(lines + 1); /* allocate new screen arrays */
  1528.         VSIw->attrst[0] = VSInewlines(lines + 1);
  1529.         if (!VSIw->linest[0] || !VSIw->attrst[0])
  1530.           /* aarrgghh -- still out of memory -- give up */
  1531.           /* shouldn't I free the block if I got only one? */
  1532.             return(-2);
  1533.         VSIw->buftop = VSIw->linest[0];
  1534.         VSIw->numlines = 0; /* nothing in scrollback */
  1535.       } /* if */
  1536.  
  1537.     VSIw->scrntop = VSIw->linest[0];            /* new top of screen */
  1538.     VSIw->vistop = VSIw->scrntop;                /* Force a scroll to the top of the screen */
  1539.     VSIlistndx(VSIw->scrntop, VSIw->attrst[0]); /* rebuild screen arrays */    
  1540.     VSIw->attrst[0]->prev = VSIw->attrst[lines];    /* Make attribute list circular */
  1541.     VSIw->attrst[lines]->next = VSIw->attrst[0];
  1542.     if (!VSIw->savelines)
  1543.       {
  1544.       /* make text line list circular to indicate no extensions */
  1545.         VSIw->linest[lines]->next = VSIw->linest[0];
  1546.         VSIw->linest[0]->prev = VSIw->linest[lines];
  1547.       } /* if */
  1548.  
  1549.   /* initialize the new screen lines to blank text and no attributes */
  1550.     for (i = 0; i <= lines; i++)
  1551.       {
  1552.         tempa = VSIw->attrst[i]->text;
  1553.         temp = VSIw->linest[i]->text;
  1554.         for (j = 0; j <= VSIw->allwidth; j++)
  1555.           {
  1556.             *temp++ = ' ';
  1557.             *tempa++ = 0;
  1558.           } /* for */
  1559.       } /* for */
  1560.   /* reset scrolling region */
  1561.     VSIw->top = 0;
  1562.     VSIw->bottom = lines;
  1563.  /* reset visible region */
  1564.     VSIw->Rtop = 0;
  1565.     VSIw->Rbottom = lines;
  1566.  
  1567.   /* dispose of old screen arrays and attribute lines */
  1568.     VSIfreelinelist(attrst[0]);
  1569.     DisposPtr((Ptr) attrst);
  1570.     DisposPtr((Ptr) linest);
  1571.     
  1572.     VSredraw(w, 0, 0, VSIw->maxwidth, lines); /* draw new blank screen */
  1573.     RSbufinfo(w, VSIw->numlines, VSIw->Rtop, VSIw->Rbottom); /* adjust vertical scroll bar */
  1574.  
  1575.     return(VSIw->lines);
  1576.  
  1577. } /* VSsetlines */
  1578.  
  1579.  
  1580. /*--------------------------------------------------------------------------*/
  1581. /* NCSA: SB - VSsetcols                                                     */
  1582. /*     This allows external procedures to set the column width.  Used by         */
  1583. /*    routines in main, to allow ARBITRARY column widths                        */
  1584. /*--------------------------------------------------------------------------*/
  1585. short VSsetcols(short w, short myWidth)                                    /* NCSA: SB */
  1586. {                                                                    /* NCSA: SB */
  1587.     if (VSvalids(w) != 0)                                            /* NCSA: SB */
  1588.         return(-1);                                                    /* NCSA: SB */
  1589.     VSIw->maxwidth = myWidth;                                        /* NCSA: SB */
  1590. }                                                                     /* NCSA: SB */
  1591.  
  1592.  
  1593. /*--------------------------------------------------------------------------*/
  1594. /* NCSA: SB - VSgetcols                                                     */
  1595. /*     This returns the column width.  Used by SetScreenDimensions, when        */
  1596. /*    the procedure needs to know the initial column width                    */
  1597. /*--------------------------------------------------------------------------*/
  1598. short VSgetcols(short w)                                                /* NCSA: SB */
  1599. {                                                                    /* NCSA: SB */
  1600.     if (VSvalids(w) != 0)                                            /* NCSA: SB */
  1601.         return(-1);                                                    /* NCSA: SB */
  1602.     return VSIw->maxwidth;                                            /* NCSA: SB */
  1603. }                                                                     /* NCSA: SB */
  1604.